/*
 * java_jvm.c
 *
 * This file is (C) 2010 by the developers of pidgin-java.
 *
 * Pidgin, Finch, and libpurple are owned by their respective developers:
 * see http://pidgin.im
 *
 * This file is part of pidgin-java.
 *
 * pidgin-java is free software: you can redistribute it and/or modify
 * it under the terms of the GNU General Public License as published by
 * the Free Software Foundation, either version 3 of the License, or
 * (at your option) any later version.
 *
 * pidgin-java is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU General Public License for more details.
 *
 * You should have received a copy of the GNU General Public License
 * along with pidgin-java.  If not, see <http://www.gnu.org/licenses/>.
 */

#include "internal.h"
#include "java_jvm.h"
#include "java_strings.h"
#include "debug.h"
#include <jni.h>

#define JAVA_PLUGIN_LOADER_CLASS		"us/neuheisel/pidgin/core/PidginPluginLoader"
#define JAVA_PLUGIN_PROBE_METHOD_NAME	"probe"
#define JAVA_PLUGIN_PROBE_METHOD_SIG	"(Ljava/lang/string;)Lus/neuheisel/pidgin/core/PidginPlugin;"

static JavaVM *s_jvm = NULL;
static JNIEnv *s_env = NULL;

gboolean
java_jvm_load(void)
{
	jint rv;
	JavaVMInitArgs vm_args;
	JavaVMOption options[1];

	options[0].optionString = N_("-Djava.class.path=.");
	options[0].extraInfo = NULL;

	vm_args.version = JNI_VERSION_1_4;
	vm_args.nOptions = 1;
	vm_args.options = options;
	vm_args.ignoreUnrecognized = JNI_FALSE;

	rv = JNI_CreateJavaVM(&s_jvm, (void **) &s_env, (void *) &vm_args);
	if (JNI_OK != rv) {
		purple_debug_error(N_("java"), _("Failed to create the Java VM: %d\n"), (int) rv);

		return FALSE;
	}

	return TRUE;
}

gboolean
java_jvm_unload(void)
{
	(void) (*s_jvm)->DestroyJavaVM(s_jvm);
	s_jvm = NULL;
	s_env = NULL;

	return TRUE;
}

gboolean
java_jvm_probe_plugin(PurplePlugin *plugin)
{
	gchar *s, *t;
	jclass pluginLoaderClass = NULL;
	jmethodID pluginLoaderMethod = NULL;
	jstring pluginPath = NULL;
	jobject pluginObject = NULL;

	/*
	 * Load the plugin loader class
	 */
	s = utf8z_to_modutf8(N_(JAVA_PLUGIN_LOADER_CLASS));
	if (NULL != s) {
		pluginLoaderClass = (*s_env)->FindClass(s_env, s);
		g_free(s);
	}

	if (NULL != pluginLoaderClass) {
		s = utf8z_to_modutf8(N_(JAVA_PLUGIN_PROBE_METHOD_NAME));
		if (NULL != s) {
			t = utf8z_to_modutf8(N_(JAVA_PLUGIN_PROBE_METHOD_SIG));
			if (NULL != t) {
				pluginLoaderMethod = (*s_env)->GetMethodID(s_env, pluginLoaderClass, s, t);
				g_free(t);
			}

			g_free(s);
		}
	}

	if (NULL == pluginLoaderMethod) {
		if (NULL != pluginLoaderClass) {
			(*s_env)->DeleteLocalRef(s_env, pluginLoaderClass);
		}

		(*s_env)->ExceptionClear(s_env);
		purple_debug_error(N_("java"), _("Failed to load the plugin loader class\n"));

		return FALSE;
	}

	/*
	 * Call the static probe method
	 */
	s = g_filename_to_utf8(plugin->path, -1, NULL, NULL, NULL);
	if (NULL != s) {
		glong num_written;
		gunichar2 *u;

		u = g_utf8_to_utf16(s, -1, NULL, &num_written, NULL);
		if (NULL != u) {
			pluginPath = (*s_env)->NewString(s_env, u, num_written);
			if (NULL != pluginPath) {
				pluginObject = (*s_env)->CallStaticObjectMethod(s_env, pluginLoaderClass, pluginLoaderMethod, pluginPath);
				(*s_env)->DeleteLocalRef(s_env, pluginPath);
			}

			g_free(u);
		}

		g_free(s);
	}

	if (NULL == pluginObject) {
		(*s_env)->DeleteLocalRef(s_env, pluginLoaderClass);

		(*s_env)->ExceptionClear(s_env);
		purple_debug_error(N_("java"), _("Failed to probe the plugin\n"));

		return FALSE;
	}

	(*s_env)->DeleteLocalRef(s_env, pluginLoaderClass);
}
